package com.wangyin.ak47.core.netty; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.PooledByteBufAllocator; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import java.net.InetSocketAddress; import com.wangyin.ak47.common.Ak47Constants; import com.wangyin.ak47.common.Logger; import com.wangyin.ak47.core.HandlerChain; import com.wangyin.ak47.core.Pipe; import com.wangyin.ak47.core.Service; import com.wangyin.ak47.core.driver.SimpleDriver; import com.wangyin.ak47.core.handler.BlockingQueueDriverHandler; import com.wangyin.ak47.core.handler.CodecDriverHandler; import com.wangyin.ak47.core.handler.FilterDriverHandler; import com.wangyin.ak47.core.handler.LoggingTrafficHandler; import com.wangyin.ak47.core.handler.HandlerInitializer; import com.wangyin.ak47.core.handler.ServiceDriverHandler; public class NettySimpleDriver<Q, R> implements SimpleDriver<Q, R>{ private static final Logger log = new Logger(NettySimpleDriver.class); protected String addr; protected int port; @Override public void setAddr(String addr) { this.addr = addr; } @Override public void setPort(int port) { this.port = port; } protected Pipe<Q, R> pipe; protected HandlerInitializer<Q, R> stubInitializer; protected HandlerInitializer<Q, R> userInitializer; @Override public void userInitializer(HandlerInitializer<Q, R> userInitializer) { this.userInitializer = userInitializer; } private ServiceDriverHandler<Q, R> serviceDriverHandler; public void addService(String name, Service<Q, R> service){ serviceDriverHandler.addService(name, service); } public void delService(String name){ serviceDriverHandler.removeService(name); } protected Bootstrap bootstrap; protected Channel channel; protected BlockingQueueDriverHandler<Q, R> blockingQueueDriverHandler; public NettySimpleDriver(Pipe<Q, R> pipe){ this.pipe = pipe; initDriverHandler(); } protected void initDriverHandler(){ final LoggingTrafficHandler<Q, R> logTrafficHandler = new LoggingTrafficHandler<Q, R>(); final CodecDriverHandler<Q, R> codecDriverHandler = new CodecDriverHandler<Q, R>(pipe); final FilterDriverHandler<Q, R> filterDriverHandler = new FilterDriverHandler<Q, R>(pipe); serviceDriverHandler = new ServiceDriverHandler<Q, R>(); blockingQueueDriverHandler = new BlockingQueueDriverHandler<Q, R>(); stubInitializer = new HandlerInitializer<Q, R>(){ @Override public void initHandler(HandlerChain<Q, R> chain) { chain.addLast("LoggingTrafficHandler", logTrafficHandler); chain.addLast("CodecDriverHandler", codecDriverHandler); chain.addLast("FilterDriverHandler", filterDriverHandler); chain.addLast("ServiceDriverHandler", serviceDriverHandler); chain.addLast("BlockingQueueDriverHandler", blockingQueueDriverHandler); } }; } private void initBootstrap(){ final NioEventLoopGroup workerGroup = new NioEventLoopGroup(); bootstrap = new Bootstrap(); bootstrap .group(workerGroup) .channel(NioSocketChannel.class) .option(ChannelOption.SO_REUSEADDR, true) .option(ChannelOption.TCP_NODELAY, true) .option(ChannelOption.SO_RCVBUF, Ak47Constants.SO_RCVBUF) .option(ChannelOption.SO_SNDBUF, Ak47Constants.SO_SNDBUF) .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { NettyChannel<Q, R> channel = new NettyChannel<Q, R>(ch); channel.chain().addLast("StubInitializer", stubInitializer); if( userInitializer != null ){ channel.chain().addLast("UserInitializer", userInitializer); } NettyChannelHandlerAdapter<Q, R> nettyChannelHandler = new NettyChannelHandlerAdapter<Q, R>(channel, pipe, pipe.newExecutor()); ch.pipeline().addLast("NettyChannelHandlerAdapter", nettyChannelHandler); } }); log.debug("Driver init success."); } @Override public R send(final Q q) throws Exception { if( null == bootstrap ){ initBootstrap(); } if( null == q ){ throw new IllegalArgumentException("Q is null."); } if( null != channel && !channel.isActive() ){ channel.close(); channel = null; } if( channel == null ){ channel = bootstrap.connect(new InetSocketAddress(addr, port)) .awaitUninterruptibly().channel(); // bootstrap // .connect(new InetSocketAddress(addr, port)) // .addListener(new ChannelFutureListener(){ // @Override // public void operationComplete(ChannelFuture future) // throws Exception { // if( future.isSuccess() ){ // channel = future.channel(); // blockingQueueDriverHandler.send(q); // }else{ // throw new Ak47RuntimeException("Fail to connect to "+addr+":"+port); // } // } // // }); } blockingQueueDriverHandler.send(q); return blockingQueueDriverHandler.recv(); } @Override public R sendAndClose(Q q) throws Exception { R r = send(q); close(); return r; } @Override public void close() throws Exception{ if( channel != null && channel.isActive() ){ channel.close().sync(); } } /** * 释放所有资源,不可再使用 */ public void release(){ try { close(); } catch (Exception e) { } bootstrap.group().shutdownGracefully(); channel = null; bootstrap = null; } }